/*
    Speedbump aka Project Kimbula
    Copyright (C) 2010  Ping Shin Ching

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCRATE_HANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses.

	Ping Shin Ching
	righteous.ninja@gmail.com OR ping_sc@hotmail.com
	More information at http://www.tidytutorials.com/p/speedbump.html
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "ratehandler.h"
#include "application.h"
#include "logger.h"

RateHandler::RateHandler(){
	int i;
	lastupdatedtime	= 0;
	updatecounter	= 1;

	for(i=0;i< RATE_HANDLER_TICKS;i++){
		handlerticks[i]=-1;
	}

}
/*************************************************************************
 * Called by handler.c to restrict the connection speed to the allocated
 * connection speed
 *************************************************************************/
int RateHandler::CalculateRate(unsigned int bytes, unsigned int processedbytes, unsigned int ratelimit, int ratereduction){
	int j;
	unsigned int totalbytes, rate, defaultrate, timetoshwayshway;
	int totalcounter;
	time_t now;
	unsigned int diff;

	now	= time(0);
	
	if(now<lastupdatedtime)
		return 1;

	diff = (now - lastupdatedtime);

	if(diff != 0){
		if(diff < RATE_HANDLER_TICKS){
			for(j = RATE_HANDLER_TICKS-1 - diff ; j >=0  ; j-- )
				handlerticks[j+diff] = handlerticks[j];
		}

		if(diff> RATE_HANDLER_TICKS){
			for(j = 1; j < RATE_HANDLER_TICKS ; j++)
				handlerticks[j] = -1;
		}
		else{
			for(j = 1; j < diff; j++)
				handlerticks[j] = 0;
		}
		handlerticks[0]=0;
		lastupdatedtime=now;
	}

	handlerticks[0]+=bytes;
	
	totalbytes=0;
	totalcounter=0;
	for(j=0;j<RATE_HANDLER_TICKS;j++){
		if(handlerticks[j]!=-1){
			totalbytes+=handlerticks[j];
			totalcounter++;
		}
	}
	
	rate=(totalbytes/totalcounter)*8;

	if(rate > (defaultrate=getmodifiedrate(ratelimit, processedbytes, ratereduction))){
		timetoshwayshway = (float)((rate-defaultrate) * (++updatecounter) * 1000000.0)/(float)defaultrate;
		logd<<"Internal rate over "<<std::dec<<rate<<" > "<<defaultrate<<" usleep("<<timetoshwayshway<<")"<<lend;
		usleep(timetoshwayshway);
	}
	else{
		logd<<"Internal rate under "<<std::dec<<rate<<" < "<<defaultrate<<lend;
		updatecounter=1;
	}

	/*
	//Show the array for debugging purposes
	memset(tmps64, 0, 64);
	for(j=0;j<RATE_HANDLER_TICKS;j++){
		sprintf(tmps64+strlen(tmps64),"%d ", handlerticks[j]);
	}
	printf("---------%s\n",tmps64);
	*/

	return 1;
}


/*************************************************************************
 * Called to further reduce the rate depending on certain thresholds
 *************************************************************************/
unsigned int RateHandler::getmodifiedrate(unsigned int defaultrate, unsigned int totalbytes, int ratereduction){
	
	double reduction =((double)ratereduction/100.0);

	if(totalbytes < D_10MB){
		return defaultrate;
	}
	else if(totalbytes< D_100MB){
		return ((double)defaultrate)*reduction;
	}
	else if(totalbytes < D_1GB){
		return ((double)defaultrate)*reduction*reduction;
	}
	else{
		return ((double)defaultrate)*reduction*reduction*reduction;
	}
}
